#include <stdio.h>
#include <stdlib.h>
#include "CuString.h"

__device__ CuString CuString::number(int32_t num)
{
    return number((int64_t)num);
}

__device__ CuString CuString::number(uint32_t num)
{
    return number((uint64_t)num);
}

__device__ CuString CuString::number(int64_t self)
{
    uint64_t num;
    bool neg = self < 0;
    if (neg)
    {
        num = (uint64_t)(-self);
    }
    else
    {
        num = self;
    }

    CuString result = CuString::number(num);
    if (neg)
        result = "-" + result;
    return result;
}

__device__ CuString CuString::number(uint64_t num)
{
    uint64_t zero = 0;
    uint64_t ten = 10;

    CuString result;
    while (num != zero) {
        uint64_t remainder = num % ten;
        result = static_cast<char>(remainder + '0') + result;
        num = num / ten;
    }
    if (result.isEmpty()) {
        result = "0";
    }
    return result;
}

__device__ CuString::CuString()
{
    m_data.resize(1);
    m_data[0] = 0;
}

bool CuString::operator==(const CuString& other) const
{
    if (m_data.size() != other.m_data.size())
        return false;

    for (int i = 0; i < other.m_data.size(); i++)
    {
        if (m_data[i] != other.m_data[i])
            return false;
    }
    return true;
}

bool CuString::operator!=(const CuString& other) const
{
    return !(*this == other);
}

void CuString::operator+=(const CuString& other)
{
    int self_size = size();
    int other_size = other.size();
    m_data.resize(self_size + other_size + 1);

    for (int i = 0; i < other_size; i++)
    {
        m_data[self_size + i] = other.m_data[i];
    }
    m_data[self_size + other_size] = 0;
}

__device__ char& CuString::operator[](int index)
{
    assert(index >= 0 && index < size());
    return m_data[index];
}

__device__ const char& CuString::operator[](int index) const
{
    assert(index >= 0 && index < size());
    return m_data[index];
}

__device__ int CuString::size() const
{
    return m_data.size() - 1;
}

__device__ CuString::CuString(const char *str)
{
    int len = cuStrlen(str);
    m_data.resize(len + 1);
    for(int i = 0 ; i < len; i++)
        m_data[i] = str[i];

    m_data[len] = 0;
}

__device__ bool CuString::isEmpty() const
{
    return m_data.size() == 1;
}

__device__ const char *CuString::c_str() const
{
    return m_data.data();
}

__device__ bool CuString::endsWith(const CuString& str) const
{
    int str_size = str.size();
    if (size() < str_size)
        return false;

    int start = size() - str_size;
    for (int i = start; i < size(); i++)
    {
        if (m_data[i] != str.m_data[i - start])
            return false;
    }
    return true;
}

__device__ bool CuString::startWith(const CuString& str) const
{
    int str_size = str.size();
    if (size() < str_size)
        return false;

    for (int i = 0; i < str_size; i++)
    {
        if (m_data[i] != str.m_data[i])
            return false;
    }
    return true;
}

__device__ int CuString::indexOf(const CuString& other,int start) const
{
    int self_size = size();
    int other_size = other.size();
    for (int i = start; i < self_size; i++)
    {
        bool find = true;
        for (int j = 0; j < other_size; j++)
        {
            if (m_data[i] != other.m_data[j])
            {
                find = false;
                break;
            }
        }

        if (find)
            return i;
    }

    return -1;
}

__device__ CuVector<CuString> CuString::split(const CuString& gap) const
{
    CuVector<CuString> ret;    
    int start = 0;
    int size = this->size();
    while (start < size)
    {
        int index = indexOf(gap, start);
        if (index == -1)
        {
            ret.push_back(mid(start));
            break;
        }

        ret.push_back(mid(start, index - start));
        start = index + gap.size();
    }
    return ret;
}

__device__ CuString CuString::left(int num) const
{
    CuString ret;
    int cur_len = size();
    if (num > cur_len)
        num = cur_len;

    ret.m_data = m_data.mid(0, num);
    ret.m_data.push_back(0);
    return ret;
}

__device__ CuString CuString::mid(int start, int len) const
{
    CuString ret;
    int cur_len = size();
    if (len == -1)
        len = cur_len - start;
    if (start + len > cur_len)
        len = cur_len - start;

    ret.m_data = m_data.mid(start, len);
    ret.m_data.push_back(0);
    return ret;
}

__device__ void CuString::chop(int count)
{
    int remain = m_data.size() - count - 1;
    if (remain < 0)
        remain = 0;
    m_data.resize(remain + 1);
    m_data[remain] = 0;
}

__device__ CuString operator+(const CuString& str, const CuString& str2)
{
    CuString ret = str;
    ret += str2;
    return ret;
}

__device__ CuString operator+(const char *str,const CuString &str2)
{
    return CuString(str) + str2;
}

__device__ CuString operator+(const CuString &str,const char *str2)
{
    return str + CuString(str2);
}

__device__ CuString operator+(char c,const CuString &str)
{
    CuString ret = str;
    ret.m_data.insert(0,c);
    return ret;
}

__device__ CuString operator+(const CuString &str, char c)
{
    CuString ret = str;
    ret.m_data.back() = c;
    ret.m_data.push_back(0);
    return ret;
}

__device__ int cuStrlen(const char *str)
{
    int len = 0;
    while(true)
    {
        if(str[len] == 0)
            return len;
        
        len++;
    }
    return -1;
}

__device__ CuString cuStrJoin(const CuStringList& list, const CuString& gap)
{
    CuString ret;
    for (int i = 0; i < list.size(); i++)
    {
        ret += list[i];
        if (i != list.size() - 1)
            ret += gap;
    }
    return ret;
}